#include <iostream>
#include <iterator>

#include "mySolution.h"

mySolution::mySolution()
  : edaSolution(),
    graph(NULL),
    modified(true)
{
}

mySolution::mySolution(const Graph &_graph) 
  : edaSolution(),
    graph(new Graph(_graph)),
    modified(true)
{
  init();
}

mySolution::mySolution(const Graph &_graph,
    const mySolution &sol)
  : vector<unsigned int>(sol),
    edaSolution(sol),
    graph(new Graph(_graph)),
    modified(true)
{
}

mySolution::mySolution(const mySolution &sol)
  : vector<unsigned int>(sol),
    edaSolution(sol),
    graph(new Graph(*(sol.graph))),
    modified(true)
{
}

mySolution::~mySolution()
{
  if (graph != NULL)
  {
    delete graph;
  }
}

void mySolution::init()
{
  printDebug(4, "Graph size: " << graph->size());

  for (unsigned int i = 0; i < graph->size(); i++)
  {
    push_back(i);
  }

  // Swap cities
  for (unsigned int i = 0; i < graph->size(); i++)
  {
    unsigned int j = (unsigned int) (graph->size() * ((float)rand() / (RAND_MAX + 1.0)));

    // Swap
    unsigned int city = (*this)[i];
    (*this)[i] = (*this)[j];
    (*this)[j] = city;
  }
}

edaSolution* mySolution::clone() const
{
  printDebug(4, "cloning...");
  edaSolution *ns = new mySolution(*this);
  printDebug(4, "cloning done");
  return ns;
}

double mySolution::fullEvaluate()
{
  if ( modified ){
    double len = .0;
    for (unsigned int i = 0; i < graph->size(); i++)
    {
      len -= graph->distance( (*this)[i], (*this)[(i + 1) % graph->size()]);
    }
    modified = false;
    cost = len;
  }
  return cost;
}

double mySolution::partialEvaluate()
{
  return fullEvaluate();
}

void mySolution::Serialize( edaBuffer &buf, bool pack )
{
  edaSolution::Serialize(buf, pack);

  if (pack)
  {
    // Pack the Graph
    graph->doSerialize(buf, pack);

    // then pack the vector
    unsigned _size = this->size();
    buf.Pack(&_size, 1);

    vector<unsigned int>::iterator iter;
    for (iter = this->begin(); iter != this->end(); iter++)
    {
      buf.Pack((unsigned int *) &(*iter), 1);
    }
  }
  else
  {
    // Unpack the Graph
    if (graph != NULL)
    {
      delete graph;
    }
    graph = (Graph*) classGenerateFromBuffer(buf);

    // then unpack the vector
    unsigned _size;
    buf.UnPack(&_size, 1);
    this->resize(_size);

    for (unsigned i = 0; i < _size; i++)
    {
      int atom;
      buf.UnPack((int *) &atom, 1);
      (*this)[i] = atom;
    }
  }
}

void mySolution::printOn(ostream &os) const
{
  copy( (*this).begin(), (*this).end(), ostream_iterator<int>( os, " " ) );
}

edaSolution& mySolution::operator = (const edaSolution &sol)
{
  vector<unsigned int>::operator = ((mySolution&) sol);
  modified = true;
  return (*this);
}

bool mySolution::operator == (const edaSolution &sol) const
{
  return (*this) == sol;
}

void mySolution::setModified( bool status )
{
  modified = status;
}
